/****************************************************************
 ** Product  :   HP Subscriber Network Application Policy
 ** Module   :   gr-manager
 ** Date: Apr 10, 2015               
 ** Author: Joey Yi
 ** (C) Copyright 2015, Hewlett-Packard Company, All Rights Reserved.
 ** This software is the proprietary information of HP, Inc.  
 ** Use is subject to license terms.
 *****************************************************************
 ** Description:   
 **    Unmarshal task configuration file to GRMType object and extract task type and action plan objects into related maps.
 **    It can find quickly  what you need task type and action plan.
 **  
 ****************************************************************/
package com.hp.snap.gr.utils;

import com.hp.snap.gr.exception.GRMException;
import com.hp.snap.gr.model.jaxb.ActionPlanType;
import com.hp.snap.gr.model.jaxb.ActionType;
import com.hp.snap.gr.model.jaxb.GRMType;
import com.hp.snap.gr.model.jaxb.TaskType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Unmarshal task configuration file to GRMType object and extract task type and action plan objects into related maps.
 * It can find quickly  what you need task type and action plan.
 *
 * <P>
 * Version: 3.3 <br>
 * Author: Joey Yi
 * Date: Apr 10, 2015
 * 
 * </P>
 *
 **/
public class GRMTaskHelper {
    private static final Logger logger = LoggerFactory.getLogger(GRMTaskHelper.class);
    private static GRMType grm;

    private static Map<String, TaskType> taskMap = new LinkedHashMap<String, TaskType>();

    private static Map<String, ActionPlanType> actionPlanMap = new LinkedHashMap<String, ActionPlanType>();

    private static Map<String, ActionType> actionMap = new LinkedHashMap<String, ActionType>();

    public static synchronized GRMType unmarshalGRM(String taskConfigurationFileName) throws GRMException {
        if (grm != null) {
            return grm;
        }

        String grmTasksConfig = Constants.USER_GR_CONF + File.separator + taskConfigurationFileName;
        if (logger.isDebugEnabled()) {
            logger.debug("Starting to unmarshal GRM task config: {}", grmTasksConfig);
        }
        
        InputStream is = null;    
        try {
            File file = new File(grmTasksConfig);
            JAXBContext jaxbContext = JAXBContext.newInstance(GRMType.class);
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            
            if (file.exists()) {
                if (logger.isTraceEnabled()) {
                    logger.trace("load tasks configuration from file: {}", file.getAbsolutePath());
                }
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                dbf.setExpandEntityReferences(false);
                dbf.setValidating(false);
                dbf.setNamespaceAware(true);
                DocumentBuilder db = dbf.newDocumentBuilder();
                Document document = db.parse(file);
                grm = (GRMType) jaxbUnmarshaller.unmarshal(document);

            } else {
                if (logger.isTraceEnabled()) {
                    logger.trace("load internal tasks configuration");
                }
                is = Thread.currentThread().getContextClassLoader().getResourceAsStream(taskConfigurationFileName);
                grm = (GRMType) jaxbUnmarshaller.unmarshal(is);

            }
        
            // tasks
            List<TaskType> taskTypes = grm.getTask();
            for (TaskType taskType : taskTypes) {
                taskMap.put(taskType.getName(), taskType);
            }

            // action plans
            List<ActionPlanType> actionPlanTypes = grm.getActionPlan();
            for (ActionPlanType actionPlanType : actionPlanTypes) {
                actionPlanMap.put(actionPlanType.getName(), actionPlanType);
            }

            // actions
            for (Method m : GRMType.class.getMethods()) {
                boolean isAction = false;
                if (m.getGenericReturnType() instanceof ParameterizedType) {
                    ParameterizedType type = (ParameterizedType) m.getGenericReturnType();
                    for (Type arg : type.getActualTypeArguments()) {
                        if (arg instanceof Class) {
                            Class clazz = (Class) arg;
                            if (clazz.getSuperclass() != null && clazz.getSuperclass() == ActionType.class) {
                                isAction = true;
                                break;
                            }
                        }
                    }
                }
                if (isAction) {
                    List lst = (List) m.invoke(grm);
                    if (lst != null && !lst.isEmpty()) {
                        for (Object obj : lst) {
                            ActionType actionType = (ActionType) obj;
                            actionMap.put(actionType.getName(), actionType);
                        }
                    }
                }
            }

        } catch (FileNotFoundException e) {
            throw new GRMException("GRM Task config file cannot be found!", e);
        } catch (JAXBException e) {
            throw new GRMException("GRM Task config file unmarshal failed!", e);
        } catch (Exception e) {
            throw new GRMException("GRM Task parsing and pooling failed!", e);
        } finally {
            // releases system resources associated with this stream
            if(is!=null) {
                try {
                    is.close();
                } catch (IOException e) {
                    //e.printStackTrace();
                    logger.warn("Cannot release {"+ is + "}.");
                }
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Unmarshal GRM task config done!");
        }

        return grm;
    }

    public static GRMType getGrm() {
        return grm;
    }

    public static Map<String, TaskType> getTaskMap() {
        return taskMap;
    }

    public static Map<String, ActionPlanType> getActionPlanMap() {
        return actionPlanMap;
    }

    public static Map<String, ActionType> getActionMap() {
        return actionMap;
    }
}
